package org.com.yz.dubbo.service.impl;

import cn.hutool.core.date.DateTime;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringEscapeUtils;
import org.com.yz.common.constant.PayConstant;
import org.com.yz.common.util.*;
import org.com.yz.dal.dao.mapper.DepositTransactionMapper;
import org.com.yz.dal.dao.mapper.HisAccntMchSubMapper;
import org.com.yz.dal.dao.mapper.HisAccntProfileMapper;
import org.com.yz.dal.dao.mapper.MchAccntMapper;
import org.com.yz.dal.dao.model.*;
import org.com.yz.dubbo.api.service.IDispatchMchAccntService;
import org.com.yz.dubbo.api.service.IMchConfigService;
import org.com.yz.dubbo.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;


/**
 * 分账接口实现类
 */
@Service(version = "1.0.0", interfaceName = "org.com.yz.dubbo.api.service.IDispatchMchAccntService")
public class DispatchMchAccntServiceImpl implements IDispatchMchAccntService {

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock( );
    private static final MyLog _log = MyLog.getLog(DispatchMchAccntServiceImpl.class);

    @Autowired
    private StringRedisTemplate redisTemplate;


    @Autowired
    private DepositTransactionMapper depositTransactionMapper;//事务dao
    @Autowired
    private MchAccntMapper mchAccntMapper;//账户dao
    @Autowired
    private BaseService baseService;
    @Autowired
    private HisAccntMchSubMapper hisAccntMchSubMapper;
    @Autowired
    private HisAccntProfileMapper hisAccntProfileMapper;
    @Autowired
    private IMchConfigService iMchConfigService;

    private static String versionNo = "1.0.2";//客户版本号


    /**
     * 分账
     * 如果是分账给供应商（查询商户配置表，是否担开启担保账户），需要增加账期控制，
     * 即先分账到供应商待结算账户（根据供应商账户号对应的外部子账户号，查询类型为供应商待结算账户）
     * 再根据账期到账规则，定时或通过发指令转账至供应商子账户
     * param parmJson
     * return
     */
    @Override
    public Map dispatch(String parmJson) throws InterruptedException {
        String result = StringEscapeUtils.unescapeJava(parmJson);
        DispatchInfo req = JSONObject.parseObject(result, DispatchInfo.class);
        List<Accnt> accntList = req.getBizContent( ).get("split_accnt_detail");//请求业务参数
        Accnt resultAccnt = null;//返回分账实例
        List<Accnt> accntLists = new ArrayList<>( );//返回分账结果集合（装有分账成功或失败的的集合）
        Map<String,Object> contentMap = new HashMap<>( );//返回分账集合map

        int successCount = 0;          //分账成功次数（大于0即整体请求成功，反之失败）
        String mchNo = req.getMchNo( );//商户号
        String transcationNo = UUID.randomUUID( ).toString( ).replace("-", "").toLowerCase( );//事务号
        Long amount = 0L;//事件金额
        //0.计算手续费
        int transFee = getTransFee(amount, accntList);
        RedisLock redisLock3 = new RedisLock(redisTemplate, "dispatchLock", 10 * 10000000, 5000000);
        //分账
        try {
            if (redisLock3.tryLock()) {
                //循环遍历参数列表，根据账户类型依次进行分账，插入对应的资金交易明细表
                for (Accnt accnt : accntList) {
                    _log.info("正常开始。。");
                    resultAccnt = new Accnt( );
                    String mchAccntNo = accnt.getMchAccntNo( );//账户号
                    String dispatchType = accnt.getDispatchType( );//分账类型
                    amount = accnt.getAmount( );//单次请求分账金额
                    if (dispatchType.equals("2")) {//1:正交易，2：反交易
                        amount = 0 - amount;
                    }
                    //1.判断订单号是否重复，如果重复，则提示订单号重复，并返回已分账信息
                    //校验必输参数合法性，如果不合法，则提示必输参数不能为空
                    if (!checkOrderNo(mchNo, accnt.getOrderNo( ), resultAccnt) && !checkMustPramter(mchNo, accnt, resultAccnt)) {
                        Date date =  new DateTime();
                        dispatchRecord(mchNo, mchAccntNo, resultAccnt, accnt, amount, transFee, transcationNo, successCount,date);
                    }

                    boolean hhFlag = "MH20181219170218hGI2".equals(mchNo) || "MH20181203135017GO5r".equals(mchNo);

                    resultAccnt.setMchAccntNo(accnt.getMchAccntNo( ));//绑定账户号
                    resultAccnt.setOrderNo(accnt.getOrderNo( ));//订单号
                    resultAccnt.setTransNo(accnt.getTransNo( ));
                    resultAccnt.setDispatchEvent(accnt.getDispatchEvent( ));//分账事件
                    resultAccnt.setDispatchType(accnt.getDispatchType( ));//分账类型
                    if (!hhFlag){
                        resultAccnt.setAmount(amount);//分账金额
                    }
                    accntLists.add(resultAccnt);
                }
                contentMap.put("split_accnt_detail", accntLists);
                _log.info("正常分账中。。");
            }
            //插入事务表
            int flag4 = insertTranction(transcationNo, req);

            if (flag4 < 0) {
                _log.info("插入子商户账户资金明细数据失败");
            }

        }catch (Exception e){
            e.printStackTrace();
            contentMap.put("errMsg","超时异常");
            System.out.println("超时异常");
        } finally {
            //为了让分布式锁的算法更稳键些，持有锁的客户端在解锁之前应该再检查一次自己的锁是否已经超时，再去做DEL操作，因为可能客户端因为某个耗时的操作而挂起，
            //操作完的时候锁因为超时已经被别人获得，这时就不必解锁了。 ————这里没有做
            redisLock3.unlock();
        }
       /* if(successCount==0){//如果没有一条成功，就置为失败
            resultAccnt.setStatus("2");
            contentMap.put("split_accnt_detail",null);
        }else{
            contentMap.put("split_accnt_detail",accntLists);
        }*/

        return contentMap;
    }

    /**
     * 商户支付记账
     * @param parmJson
     * @return
     * @throws InterruptedException
     */
    @Override
    public Map dispatchPay(String parmJson) throws InterruptedException {
        RedisLock redisLock3 = new RedisLock(redisTemplate, "payLock", 10 * 10000000, 5000000);
        String result = StringEscapeUtils.unescapeJava(parmJson);
        DispatchPayInfo req = JSONObject.parseObject(result, DispatchPayInfo.class);

        String transNo = (String) req.getBizContent().get("trans_no"); //交易流水号
        String chargeRate = (String) req.getBizContent().get("charge_rate"); //支付通道手续费费率
        String transChannel = (String) req.getBizContent().get("trans_channel"); //交易所属通道
        String transTime = (String) req.getBizContent().get("trans_time"); //交易完成时间
        List<Accnt> accntList = JSON.parseArray(JSON.toJSONString(req.getBizContent( ).get("split_accnt_detail")), Accnt.class);

        Accnt resultAccnt = null; //返回分账实例
        List<Accnt> accntLists = new ArrayList<>( ); //返回分账结果集合（装有分账成功或失败的的集合）
        Map<String,Object> contentMap = new HashMap<>( ); //返回分账集合map

        int successCount = 0;          //分账成功次数（大于0即整体请求成功，反之失败）
        String mchNo = req.getMchNo( );//商户号
        String transcationNo = UUID.randomUUID( ).toString( ).replace("-", "").toLowerCase( );//事务号
        Long amount = 0L;//事件金额
        //0.计算手续费
        int transFee = getTransFeeEvent(amount, chargeRate, accntList);
        //分账
        try {
            if (redisLock3.tryLock()) {
                //循环遍历参数列表，根据账户类型依次进行分账，插入对应的资金交易明细表
                for (Accnt accnt : accntList) {
                    _log.info("正常开始。。");
                    resultAccnt = new Accnt( );
                    String mchAccntNo = accnt.getMchAccntNo( );//账户号
                    String dispatchType = accnt.getDispatchType( );//分账类型
                    amount = accnt.getAmount( );//单次请求分账金额
                    if (dispatchType.equals("2")) {//1:正交易，2：反交易
                        amount = 0 - amount;
                    }
                    //1.判断订单号是否重复，如果重复，则提示订单号重复，并返回已分账信息
                    //校验必输参数合法性，如果不合法，则提示必输参数不能为空
                    if (!checkOrderNo(mchNo, accnt.getOrderNo( ), resultAccnt) && !checkMustPramterPay(mchNo, accnt, resultAccnt)) {
                        Date date =  new DateTime();
                        accnt.setTransNo(transNo);
                        accnt.setChargeRate(chargeRate);
                        accnt.setTransChannel(transChannel);
                        accnt.setTransTime(transTime);
                        dispatchRecord(mchNo, mchAccntNo, resultAccnt, accnt, amount, transFee, transcationNo, successCount,date);
                    }
                    resultAccnt.setMchAccntNo(accnt.getMchAccntNo( ));//绑定账户号
                    resultAccnt.setOrderNo(accnt.getOrderNo( ));//订单号
                    resultAccnt.setDispatchEvent(accnt.getDispatchEvent( ));//分账事件
                    resultAccnt.setDispatchType(accnt.getDispatchType( ));//分账类型
                    resultAccnt.setAmount(amount);//分账金额
                    accntLists.add(resultAccnt);
                }
                contentMap.put("trans_no", transNo);
                contentMap.put("split_accnt_detail", accntLists);
                _log.info("正常分账中。。");
            }
            //插入事务表
            int flag4 = insertTranction(transcationNo, req);

            if (flag4 < 0) {
                _log.info("插入子商户账户资金明细数据失败");
            }

        }catch (Exception e){
            e.printStackTrace();
            contentMap.put("errMsg","超时异常");
            System.out.println("超时异常");
        } finally {
            //为了让分布式锁的算法更稳键些，持有锁的客户端在解锁之前应该再检查一次自己的锁是否已经超时，再去做DEL操作，因为可能客户端因为某个耗时的操作而挂起，
            //操作完的时候锁因为超时已经被别人获得，这时就不必解锁了。 ————这里没有做
            redisLock3.unlock();
        }
       /* if(successCount==0){//如果没有一条成功，就置为失败
            resultAccnt.setStatus("2");
            contentMap.put("split_accnt_detail",null);
        }else{
            contentMap.put("split_accnt_detail",accntLists);
        }*/

        return contentMap;
    }

    /**
     * 商户退款记账
     * @param parmJson
     * @return
     * @throws InterruptedException
     */
    @Override
    public Map dispatchRefund(String parmJson) throws InterruptedException {
        RedisLock redisLock3 = new RedisLock(redisTemplate, "refundLock", 10 * 10000000, 5000000);
        String result = StringEscapeUtils.unescapeJava(parmJson);
        DispatchPayInfo req = JSONObject.parseObject(result, DispatchPayInfo.class);

        String transNo = (String) req.getBizContent().get("trans_no"); //交易流水号
        String refundTransNo = (String)  req.getBizContent().get("refund_trans_no"); //支付通道返回的退款订单号
        String chargeRate = (String) req.getBizContent().get("charge_rate"); //支付通道手续费费率
        String transTime = (String) req.getBizContent().get("trans_time"); //交易完成时间
        String transChannel = (String) req.getBizContent().get("trans_channel"); //支付渠道
        List<Accnt> accntList = JSON.parseArray(JSON.toJSONString(req.getBizContent( ).get("split_accnt_detail")), Accnt.class);

        Accnt resultAccnt = null; //返回分账实例
        List<Accnt> accntLists = new ArrayList<>( ); //返回分账结果集合（装有分账成功或失败的的集合）
        Map<String,Object> contentMap = new HashMap<>( ); //返回分账集合map

        int successCount = 0;          //分账成功次数（大于0即整体请求成功，反之失败）
        String mchNo = req.getMchNo( );//商户号
        String transcationNo = UUID.randomUUID( ).toString( ).replace("-", "").toLowerCase( );//事务号
        Long amount = 0L;//事件金额
        //0.计算手续费
        int transFee = getTransFeeEvent(amount, chargeRate, accntList);
        //分账
        try {
            if (redisLock3.tryLock()) {
                //循环遍历参数列表，根据账户类型依次进行分账，插入对应的资金交易明细表
                for (Accnt accnt : accntList) {
                    _log.info("正常开始。。");
                    resultAccnt = new Accnt( );
                    String mchAccntNo = accnt.getMchAccntNo( );//账户号
                    String dispatchType = accnt.getDispatchType( );//分账类型
                    amount = accnt.getAmount( );//单次请求分账金额
                    if (dispatchType.equals("2")) {//1:正交易，2：反交易
                        amount = 0 - amount;
                    }
                    //1.判断订单号是否重复，如果重复，则提示订单号重复，并返回已分账信息
                    //校验必输参数合法性，如果不合法，则提示必输参数不能为空
                    if (!checkOrderNo(mchNo, accnt.getOrderNo( ), resultAccnt) && !checkMustPramterRefund(mchNo, accnt, resultAccnt, transNo)) {
                        Date date =  new DateTime();
                        accnt.setTransNo(transNo);
                        accnt.setRefundTransNo(refundTransNo);
                        accnt.setChargeRate(chargeRate);
                        accnt.setTransTime(transTime);
                        accnt.setTransChannel(transChannel);
                        dispatchRecord(mchNo, mchAccntNo, resultAccnt, accnt, amount, transFee, transcationNo, successCount,date);
                    }
                    resultAccnt.setMchAccntNo(accnt.getMchAccntNo( ));//绑定账户号
                    resultAccnt.setOrderNo(accnt.getOrderNo( ));//订单号
                    resultAccnt.setDispatchEvent(accnt.getDispatchEvent( ));//分账事件
                    resultAccnt.setDispatchType(accnt.getDispatchType( ));//分账类型
                    resultAccnt.setAmount(amount);//分账金额
                    accntLists.add(resultAccnt);
                }
                contentMap.put("trans_no", transNo);
                contentMap.put("refund_trans_no", refundTransNo);
                contentMap.put("split_accnt_detail", accntLists);
                _log.info("正常分账中。。");
            }
            //插入事务表
            int flag4 = insertTranction(transcationNo, req);

            if (flag4 < 0) {
                _log.info("插入子商户账户资金明细数据失败");
            }

        }catch (Exception e){
            e.printStackTrace();
            contentMap.put("errMsg","超时异常");
            System.out.println("超时异常");
        } finally {
            //为了让分布式锁的算法更稳键些，持有锁的客户端在解锁之前应该再检查一次自己的锁是否已经超时，再去做DEL操作，因为可能客户端因为某个耗时的操作而挂起，
            //操作完的时候锁因为超时已经被别人获得，这时就不必解锁了。 ————这里没有做
            redisLock3.unlock();
        }
       /* if(successCount==0){//如果没有一条成功，就置为失败
            resultAccnt.setStatus("2");
            contentMap.put("split_accnt_detail",null);
        }else{
            contentMap.put("split_accnt_detail",accntLists);
        }*/

        return contentMap;
    }

    /**
     * 商户非支付退款类记账
     * @param parmJson
     * @return
     * @throws InterruptedException
     */
    @Override
    public Map dispatchOther(String parmJson) throws InterruptedException {
        RedisLock redisLock3 = new RedisLock(redisTemplate, "otherLock", 10 * 10000000, 5000000);
        String result = StringEscapeUtils.unescapeJava(parmJson);
        DispatchPayInfo req = JSONObject.parseObject(result, DispatchPayInfo.class);

        String transNo = (String) req.getBizContent().get("trans_no"); //交易流水号
        List<Accnt> accntList = JSON.parseArray(JSON.toJSONString(req.getBizContent( ).get("split_accnt_detail")), Accnt.class);

        Accnt resultAccnt = null; //返回分账实例
        List<Accnt> accntLists = new ArrayList<>( ); //返回分账结果集合（装有分账成功或失败的的集合）
        Map<String,Object> contentMap = new HashMap<>( ); //返回分账集合map

        int successCount = 0;          //分账成功次数（大于0即整体请求成功，反之失败）
        String mchNo = req.getMchNo( );//商户号
        String transcationNo = UUID.randomUUID( ).toString( ).replace("-", "").toLowerCase( );//事务号
        Long amount = 0L;//事件金额
        //0.计算手续费
        int transFee = 0; //getTransFeeEvent(amount, "", accntList);
        //分账
        try {
            if (redisLock3.tryLock()) {
                //循环遍历参数列表，根据账户类型依次进行分账，插入对应的资金交易明细表
                for (Accnt accnt : accntList) {
                    _log.info("正常开始。。");
                    resultAccnt = new Accnt( );
                    String mchAccntNo = accnt.getMchAccntNo( );//账户号
                    String dispatchType = accnt.getDispatchType( );//分账类型
                    amount = accnt.getAmount( );//单次请求分账金额
                    if (dispatchType.equals("2")) {//1:正交易，2：反交易
                        amount = 0 - amount;
                    }
                    //1.判断订单号是否重复，如果重复，则提示订单号重复，并返回已分账信息
                    //校验必输参数合法性，如果不合法，则提示必输参数不能为空
                    if (!checkOrderNo(mchNo, accnt.getOrderNo( ), resultAccnt) && !checkMustPramterOther(mchNo, accnt, resultAccnt)) {
                        Date date =  new DateTime();
                        accnt.setTransNo(transNo);
                        dispatchRecord(mchNo, mchAccntNo, resultAccnt, accnt, amount, transFee, transcationNo, successCount,date);
                    }
                    resultAccnt.setMchAccntNo(accnt.getMchAccntNo( ));//绑定账户号
                    resultAccnt.setOrderNo(accnt.getOrderNo( ));//订单号
                    resultAccnt.setDispatchEvent(accnt.getDispatchEvent( ));//分账事件
                    resultAccnt.setDispatchType(accnt.getDispatchType( ));//分账类型
                    resultAccnt.setAmount(amount);//分账金额
                    accntLists.add(resultAccnt);
                }
                contentMap.put("trans_no", transNo);
                contentMap.put("split_accnt_detail", accntLists);
                _log.info("正常分账中。。");
            }
            //插入事务表
            int flag4 = insertTranction(transcationNo, req);

            if (flag4 < 0) {
                _log.info("插入子商户账户资金明细数据失败");
            }

        }catch (Exception e){
            e.printStackTrace();
            contentMap.put("errMsg","超时异常");
            System.out.println("超时异常");
        } finally {
            //为了让分布式锁的算法更稳键些，持有锁的客户端在解锁之前应该再检查一次自己的锁是否已经超时，再去做DEL操作，因为可能客户端因为某个耗时的操作而挂起，
            //操作完的时候锁因为超时已经被别人获得，这时就不必解锁了。 ————这里没有做
            redisLock3.unlock();
        }
       /* if(successCount==0){//如果没有一条成功，就置为失败
            resultAccnt.setStatus("2");
            contentMap.put("split_accnt_detail",null);
        }else{
            contentMap.put("split_accnt_detail",accntLists);
        }*/

        return contentMap;
    }

    @Transactional(rollbackFor = Exception.class,propagation=Propagation.SUPPORTS)
    public void dispatchRecord(String mchNo, String mchAccntNo, Accnt resultAccnt, Accnt accnt, Long amount, int transFee, String transcationNo, int successCount,Date date){
        MchAccnt mchAccntBefore;
        MchAccnt mchAccntOnway;
        Date transTime = new Date( );
        mchAccntBefore = queryMchAccntByMchNo(mchNo, mchAccntNo);//分账账户信息
        mchAccntOnway = queryMchOnway(mchNo);//在途账户信息
        if (null == mchAccntBefore) {//如果账户信息为空0-0--0
            resultAccnt.setDesc(PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULLS);//分账状态描述
            resultAccnt.setCode(PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULL);//分账状态
            resultAccnt.setStatus("2");
            resultAccnt.setAmount(amount);
        } else {
            //查询商户配置信息
            MchConfig config = CacheUtil.me().getMchConfigInfo(mchNo,"0");

            //海狐海淘、顺网1.0.3新版本（生产环境、测试环境）
            boolean hhFlag = "MH20181219170218hGI2".equals(mchNo) || "MH20181203135017GO5r".equals(mchNo);
            boolean swFlag = "MH20181120110623Tji0".equals(mchNo) || "80000000".equals(mchNo);
//            if ((hhFlag || (swFlag && "1.0.3".equals(config.getVersionNo())))){
            if (hhFlag){
                if (ToolUtil.isEmpty(accnt.getTransChannel())){
                    resultAccnt.setDesc("[支付所属通道]" + PayConstant.RETURN_DEPOSIT_MUST_NULLS);//分账状态描述
                    resultAccnt.setCode(PayConstant.RETURN_DEPOSIT_MUST_NULL);//分账状态
                    resultAccnt.setStatus("2");
                    resultAccnt.setAmount(amount);
                }else {
                    if (PayConstant.DEPOSIT_SUPPLIER.equals(mchAccntBefore.getAccntType())){ //供应商子商户
                        if (ToolUtil.isNotEmpty(config) && ToolUtil.isNotEmpty(config.getUseAssurance())){
                            if ("Y".equals(config.getUseAssurance())){ //开启担保账户
                                mchAccntNo = querySuplierMchNo(mchNo, mchAccntBefore.getOutMchAccntNo()); //供应商待结算子账户
                                mchAccntBefore = queryMchAccntByMchNo(mchNo, mchAccntNo);
                                accnt.setMchAccntNo(mchAccntNo);
                            }
                        }
                    }
                    Long amt = mchAccntBefore.getRemainAmt(); //分账前账户剩余资金
                    String accntType = mchAccntBefore.getAccntType(); //账户类型

                    //手续费率不为空、非退款记账、分润账户
//                if (ToolUtil.isNotEmpty(accnt.getChargeRate()) && !"refund".equals(accnt.getDispatchEvent()) && "profit".equals(mchAccntBefore.getAccntType())){
//                    amount = amount - transFee;
//                }
                    //不按照记账的手续费率计算，默认按照千六计算
                    Double transFeeGap = 0D;
                    boolean channelFlag = "258799714".equals(accnt.getTransChannel()); //兴业通道（海狐）

                    if(accntType.equals(PayConstant.DEPOSIT_MCHSUB)){ //子商户账户
                        String chargeRate = "0.006"; //手续费率
                        String chargeRateActual = "0.0035"; //交易实际扣除费率

                        if (channelFlag){
                            Double transFeeVitual = new BigDecimal(amount).multiply(new BigDecimal(chargeRate)).setScale(0, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();

//                        Double transFeeActual = new BigDecimal(amount).multiply(new BigDecimal(chargeRateActual)).setScale(0, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();

//                        transFeeGap = transFeeVitual - transFeeActual; //手续费差额 添加到分润账户中，并添加记录，同时添加到在途账户明细及在途账户中
                            transFeeGap = new BigDecimal(amount).multiply(new BigDecimal(chargeRate).subtract(new BigDecimal(chargeRateActual))).setScale(0, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();

                            amount = amount - transFeeVitual.longValue(); //扣除手续费，分到子商户账户的金额
                        }else { //微信官方通道（海狐）
                            Double transFeeVitual = new BigDecimal(amount).multiply(new BigDecimal(chargeRate)).setScale(0, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
                            transFeeGap = transFeeVitual;
                            amount = amount - transFeeVitual.longValue(); //扣除手续费，分到子商户账户的金额
                        }
                    }

                    //实际入账金额小于分账金额、且存在平台提供活动资金
                    //活动类型不为空、活动金额不为空、子商户账户
                    if (ToolUtil.isNotEmpty(accnt.getPromotionType()) && ToolUtil.isNotEmpty(accnt.getPromotionAmt()) && "mchsub".equals(accntType)) {
                        amt = promotion(accnt, accntType, amount, mchNo, mchAccntNo, transTime, transcationNo, amt, date);
                        amount = amount - accnt.getPromotionAmt();
                    }

                    Long afertAmt = amt + amount; //分账后账户剩余资金
                    _log.info("读取到的分账后金额为：" + afertAmt);

                    //更新各个账户余额
                    //更新分账账户余额
                    int flag6 = updateMchAccnt(mchNo, mchAccntNo, amount);
                    if (flag6 < 0) {
                        _log.info("更新分帐账户失败");
                    }
                    //更新在途账户余额
                    //在途账户需要加上手续费差额
                    Long amountAfterTransFeeGap = amount + transFeeGap.longValue();
//                int flag5 = updateMchOnway(amount, mchNo);
                    int flag5 = updateMchOnway(amountAfterTransFeeGap, mchNo);
                    if (flag5 < 0) {
                        _log.info("更新在途账户失败");
                    }
                    //更新在途（类型：总额）账户余额
//                int flag3 = updateHisOnway(mchNo, amount);
                    int flag3 = updateHisOnway(mchNo, amountAfterTransFeeGap);
                    if (flag3 < 0) {
                        _log.info("更新在途1总额失败");
                    }

                    //添加各个账户表明细
                    //插入分账账户资金明细
                    if (accntType.equals(PayConstant.DEPOSIT_MCHSUB)){ //子商户
                        int flag = insertHisMchSub(transcationNo, accnt, mchNo, amt, amount, afertAmt, date);
                        if (flag < 0) {
                            _log.info("插入子商户账户资金明细数据失败");
                        }

                        //查询分润账户
                        MchAccnt mchAccnt = new MchAccnt();
                        mchAccnt.setMchNo(mchNo);
                        mchAccnt.setAccntType("profit"); //分润
                        List<MchAccnt> mchAccnts = mchAccntMapper.selectMchAccnt(mchAccnt);
                        if (!mchAccnts.isEmpty()){
                            mchAccnt = mchAccnts.get(0);

                            if (channelFlag){ //兴业通道（海狐）
                                //更新分润账户余额
                                int result = updateMchProfit(transFeeGap.longValue(), mchAccnt.getMchNo());
                                if (result < 0){
                                    _log.info("手续费差额-->更新分润账户失败");
                                }

                                Long beforeAmtProfit = mchAccnt.getRemainAmt();
                                Double afterAmtProfit = new BigDecimal(beforeAmtProfit).add(new BigDecimal(transFeeGap)).doubleValue();
                                //插入分润账户资金明细
                                int flag1 = insertHisMchProfit(transcationNo, accnt, mchNo, beforeAmtProfit, transFeeGap.longValue(), afterAmtProfit.longValue(), date);
                                if (flag1 < 0) {
                                    _log.info("手续费差额-->插入分润账户资金明细数据失败");
                                }
                            }
                        }else {
                            _log.info("手续费差额-->插入分润账户资金明细数据失败-->未找到分润账户");
                        }
                    } else if (accntType.equals(PayConstant.DEPOSIT_PROFIT)) { //分润账户
                        int flag1 = insertHisMchProfit(transcationNo, accnt, mchNo, amt, amount, afertAmt, date);
                        if (flag1 < 0) {
                            _log.info("插入分润账户资金明细数据失败");
                        }
                    } else if (accntType.equals(PayConstant.DEPOSIT_SUPPLIER_ASSURANCE)) { //供应商结算账户
                        int flag1 = insertHisSupplierAss(transcationNo, accnt, mchNo, amt, amount, afertAmt,date);
                        if (flag1 < 0) {
                            _log.info("插入分润账户资金明细数据失败");
                        }
                    } else {
                        resultAccnt.setDesc(PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULLS); //分账状态描述
                        resultAccnt.setCode(PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULL); //分账状态
                        resultAccnt.setStatus("2");
                        resultAccnt.setAmount(amount);
                    }
                    //插入在途1账户资金明细;更新在途1账户总额
                    int flag2 = insertHisOnway(transcationNo, accnt, mchAccntOnway, mchNo, amount, date);
                    if (flag2 < 0) {
                        _log.info("插入在途1资金明细数据失败");
                    }


                    //将手续费差额也记录到在途明细中
                    if (accntType.equals(PayConstant.DEPOSIT_MCHSUB)){
                        if (channelFlag) { //兴业通道
                            mchAccntOnway = queryMchOnway(mchNo); //更新在途账户信息
                            int result = insertHisOnway(transcationNo, accnt, mchAccntOnway, mchNo, transFeeGap.longValue(), date);
                            if (result < 0) {
                                _log.info("手续费差额-->插入在途1资金明细数据失败");
                            }
                        }
                    }

                    //分账成功，更新分账状态
                    resultAccnt.setCode("0000");
                    resultAccnt.setStatus("1");
                    successCount++;
                    resultAccnt.setAmountAfterEvent(afertAmt); //分账后账户余额
                    resultAccnt.setAmount(amount);
                }
            }else { //按照老版本执行
                //2.如果是分给供应商,则查询待结算供应商账户 start 2018-11-2
                if (PayConstant.DEPOSIT_SUPPLIER.equals(mchAccntBefore.getAccntType( ))) {
                    //如果开启供应商担保
                    if (ToolUtil.isNotEmpty(config) && ToolUtil.isNotEmpty(config.getUseAssurance( ))) {
                        if ("Y".equals(config.getUseAssurance( ))) {
                            //分账到供应商
                            //根据供应商账户号对应的外部子账户号，查询类型为供应商待结算账户
                            mchAccntNo = querySuplierMchNo(mchNo, mchAccntBefore.getOutMchAccntNo( ));
                            mchAccntBefore = queryMchAccntByMchNo(mchNo, mchAccntNo);//分账账户信息
                            accnt.setMchAccntNo(mchAccntNo);
                        }
                    }
                }//end  2018-11-2
                Long amt = mchAccntBefore.getRemainAmt( );//分账账户剩余资金（分账事件发生前实时金额）
                String accntType = mchAccntBefore.getAccntType( );//账户类型
                //3.如果是分润账户，则事件金额需要扣减调手续费
                if (ToolUtil.isNotEmpty(accnt.getChargeRate( )) && !"refund".equals(accnt.getDispatchEvent( )) && "profit".equals(mchAccntBefore.getAccntType( ))) {//如果需要计算手续费
                    amount = amount - transFee;
                }
                //4.若实际入账金额小于分账金额，且存在平台提供活动资金
                if (ToolUtil.isNotEmpty(accnt.getPromotionType( )) && ToolUtil.isNotEmpty(accnt.getPromotionAmt( )) && "mchsub".equals(accntType)) {
                    amt = promotion(accnt, accntType, amount, mchNo, mchAccntNo, transTime, transcationNo, amt,date);
                    amount = amount - accnt.getPromotionAmt( );
                }
                Long afertAmt = amt + amount;//账户剩余资金（分账事件发生后金额）
                _log.info("读取到的分账后金额为：" + afertAmt);

                //5.更新分账账户信息------------
                int flag6 = updateMchAccnt(mchNo, mchAccntNo, amount);
                if (flag6 < 0) {
                    _log.info("更新分帐账户失败");
                }
                //更新在途账户信息
                int flag5 = updateMchOnway(amount, mchNo);
                if (flag5 < 0) {
                    _log.info("更新在途账户失败");
                }
                int flag3 = updateHisOnway(mchNo, amount);
                if (flag3 < 0) {
                    _log.info("更新在途1总额失败");
                }
                //插入分账账户资金明细
                if (PayConstant.DEPOSIT_MCHSUB.equals(accntType)) {//子商户
                    int flag = insertHisMchSub(transcationNo, accnt, mchNo, amt, amount, afertAmt,date);
                    if (flag < 0) {
                        _log.info("插入子商户账户资金明细数据失败");
                    }
                } else if (accntType.equals(PayConstant.DEPOSIT_PROFIT)) {//分润账户
                    int flag1 = insertHisMchProfit(transcationNo, accnt, mchNo, amt, amount, afertAmt,date);
                    if (flag1 < 0) {
                        _log.info("插入分润账户资金明细数据失败");
                    }
                } else if (accntType.equals(PayConstant.DEPOSIT_SUPPLIER_ASSURANCE)) {//供应商结算账户
                    int flag1 = insertHisSupplierAss(transcationNo, accnt, mchNo, amt, amount, afertAmt,date);
                    if (flag1 < 0) {
                        _log.info("插入分润账户资金明细数据失败");
                    }
                } else {
                    resultAccnt.setDesc(PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULLS);//分账状态描述
                    resultAccnt.setCode(PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULL);//分账状态
                    resultAccnt.setStatus("2");
                }
                //插入在途1账户资金明细;更新在途1账户总额
                int flag2 = insertHisOnway(transcationNo, accnt, mchAccntOnway, mchNo, amount,date);
                if (flag2 < 0) {
                    _log.info("插入在途1资金明细数据失败");
                }
                //6.此时分账成功，更新分账状态
                resultAccnt.setCode("0000");
                resultAccnt.setStatus("1");
                successCount++;
                resultAccnt.setAmountAfterEvent(afertAmt);//分账后账户余额 //
            }
        }
    }




    /**
     * 补账
     * 分账的原有逻辑不变，如果记账类型是补账，则将在途明细的创建时间置为报文里的补账时间
     * param parmJson
     * return
     */
    @Override
    public Map dispatchRecon(String parmJson) throws InterruptedException {
        String result = StringEscapeUtils.unescapeJava(parmJson);
        DispatchInfo req = JSONObject.parseObject(result, DispatchInfo.class);
        List<Accnt> accntList = req.getBizContent( ).get("split_accnt_detail");//请求业务参数
        Accnt resultAccnt = null;//返回分账实例
        List<Accnt> accntLists = new ArrayList<>( );//返回分账结果集合（装有分账成功或失败的的集合）
        Map<String,Object> contentMap = new HashMap<>( );//返回分账集合map

        int successCount = 0;          //分账成功次数（大于0即整体请求成功，反之失败）
        String mchNo = req.getMchNo( );//商户号
        String transcationNo = UUID.randomUUID( ).toString( ).replace("-", "").toLowerCase( );//事务号
        Long amount = 0L;//事件金额
        //0.计算手续费
        RedisLock redisLock3 = new RedisLock(redisTemplate, "dispatchReconLock", 10 * 10000000, 5000000);
        int transFee = getTransFee(amount, accntList);
        //分账
        try {
            if (redisLock3.tryLock()) {
                //循环遍历参数列表，根据账户类型依次进行分账，插入对应的资金交易明细表
                for (Accnt accnt : accntList) {
                    _log.info("正常开始。。");
                    resultAccnt = new Accnt( );
                    String mchAccntNo = accnt.getMchAccntNo( );//账户号
                    String dispatchType = accnt.getDispatchType( );//分账类型
                    amount = accnt.getAmount( );//单次请求分账金额
                    if (dispatchType.equals("2")) {//1:正交易，2：反交易
                        amount = 0 - amount;
                    }
                    //1.判断订单号是否重复，如果重复，则提示订单号重复，并返回已分账信息
                    //校验必输参数合法性，如果不合法，则提示必输参数不能为空
                    if (!checkOrderNo(mchNo, accnt.getOrderNo( ), resultAccnt) && !checkMustPramter(mchNo, accnt, resultAccnt)) {
                        Date date = new DateTime();
                        dispatchRecordRecon(mchNo, mchAccntNo, resultAccnt, accnt, amount, transFee, transcationNo, successCount,date);
                    }
                    resultAccnt.setMchAccntNo(accnt.getMchAccntNo( ));//绑定账户号
                    resultAccnt.setOrderNo(accnt.getOrderNo( ));//订单号
                    resultAccnt.setTransNo(accnt.getTransNo( ));
                    resultAccnt.setDispatchEvent(accnt.getDispatchEvent( ));//分账事件
                    resultAccnt.setDispatchType(accnt.getDispatchType( ));//分账类型
                    resultAccnt.setAmount(amount);//分账金额
                    accntLists.add(resultAccnt);
                }
                contentMap.put("split_accnt_detail", accntLists);
                _log.info("正常分账中。。");
            }
            //插入事务表
            int flag4 = insertTranction(transcationNo, req);

            if (flag4 < 0) {
                _log.info("插入子商户账户资金明细数据失败");
            }

        }catch (Exception e){
            e.printStackTrace();
            contentMap.put("errMsg","超时异常");
            System.out.println("超时异常");
        } finally {
            //为了让分布式锁的算法更稳键些，持有锁的客户端在解锁之前应该再检查一次自己的锁是否已经超时，再去做DEL操作，因为可能客户端因为某个耗时的操作而挂起，
            //操作完的时候锁因为超时已经被别人获得，这时就不必解锁了。 ————这里没有做
            redisLock3.unlock();
        }
       /* if(successCount==0){//如果没有一条成功，就置为失败
            resultAccnt.setStatus("2");
            contentMap.put("split_accnt_detail",null);
        }else{
            contentMap.put("split_accnt_detail",accntLists);
        }*/

        return contentMap;
    }

    @Transactional(rollbackFor = Exception.class)
    public void dispatchRecordRecon(String mchNo, String mchAccntNo, Accnt resultAccnt, Accnt accnt, Long amount, int transFee, String transcationNo, int successCount,Date date){
        MchAccnt mchAccntBefore;
        MchAccnt mchAccntOnway;
        Date transTime = new Date( );
        mchAccntBefore = queryMchAccntByMchNo(mchNo, mchAccntNo);//分账账户信息
        mchAccntOnway = queryMchOnway(mchNo);//在途账户信息
        if (null == mchAccntBefore) {//如果账户信息为空0-0--0
            resultAccnt.setDesc(PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULLS);//分账状态描述
            resultAccnt.setCode(PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULL);//分账状态
            resultAccnt.setStatus("2");
        } else {
            //2.如果是分给供应商,则查询待结算供应商账户 start 2018-11-2
            if (PayConstant.DEPOSIT_SUPPLIER.equals(mchAccntBefore.getAccntType( ))) {
                //查询商户配置信息
                MchConfig config = CacheUtil.me( ).getMchConfigInfo(mchNo, "0");
                //如果开启供应商担保
                if (ToolUtil.isNotEmpty(config) && ToolUtil.isNotEmpty(config.getUseAssurance( ))) {
                    if ("Y".equals(config.getUseAssurance( ))) {
                        //分账到供应商
                        //根据供应商账户号对应的外部子账户号，查询类型为供应商待结算账户
                        mchAccntNo = querySuplierMchNo(mchNo, mchAccntBefore.getOutMchAccntNo( ));
                        mchAccntBefore = queryMchAccntByMchNo(mchNo, mchAccntNo);//分账账户信息
                        accnt.setMchAccntNo(mchAccntNo);
                    }
                }
            }//end  2018-11-2
            Long amt = mchAccntBefore.getRemainAmt( );//分账账户剩余资金（分账事件发生前实时金额）
            String accntType = mchAccntBefore.getAccntType( );//账户类型
            //3.如果是分润账户，则事件金额需要扣减调手续费
            if (ToolUtil.isNotEmpty(accnt.getChargeRate( )) && !"refund".equals(accnt.getDispatchEvent( )) && "profit".equals(mchAccntBefore.getAccntType( ))) {//如果需要计算手续费
                amount = amount - transFee;
            }
            //4.若实际入账金额小于分账金额，且存在平台提供活动资金
            if (ToolUtil.isNotEmpty(accnt.getPromotionType( )) && ToolUtil.isNotEmpty(accnt.getPromotionAmt( )) && "mchsub".equals(accntType)) {
                amt = promotion(accnt, accntType, amount, mchNo, mchAccntNo, transTime, transcationNo, amt,date);
                amount = amount - accnt.getPromotionAmt( );
            }
            Long afertAmt = amt + amount;//账户剩余资金（分账事件发生后金额）
            _log.info("读取到的分账后金额为：" + afertAmt);

            //5.更新分账账户信息------------
            int flag6 = updateMchAccnt(mchNo, mchAccntNo, amount);
            if (flag6 < 0) {
                _log.info("更新分帐账户失败");
            }
            //更新在途账户信息
            int flag5 = updateMchOnway(amount, mchNo);
            if (flag5 < 0) {
                _log.info("更新在途账户失败");
            }
            int flag3 = updateHisOnway(mchNo, amount);
            if (flag3 < 0) {
                _log.info("更新在途1总额失败");
            }
            //更新插入数据日期之后的时间前后余额

            Date date1 =accnt.getReconTime();
            String dates = DateUtil.date2Str(accnt.getReconTime());
            //插入分账账户资金明细
            if (PayConstant.DEPOSIT_MCHSUB.equals(accntType)) {//子商户
                int flag = insertHisMchSub(transcationNo, accnt, mchNo, amt, amount, afertAmt,date);
                if (flag < 0) {
                    _log.info("插入子商户账户资金明细数据失败");
                }

                updateHisMchSubByTime(mchNo,date1,amount,mchAccntNo);
            } else if (accntType.equals(PayConstant.DEPOSIT_PROFIT)) {//分润账户
                int flag1 = insertHisMchProfit(transcationNo, accnt, mchNo, amt, amount, afertAmt,date);
                if (flag1 < 0) {
                    _log.info("插入分润账户资金明细数据失败");
                }
                updateHisProfileByTime(mchNo,date1,amount,mchAccntNo);
            } else if (accntType.equals(PayConstant.DEPOSIT_SUPPLIER_ASSURANCE)) {//供应商结算账户
                int flag1 = insertHisSupplierAss(transcationNo, accnt, mchNo, amt, amount, afertAmt,date);
                if (flag1 < 0) {
                    _log.info("插入供应商待结算账户资金明细数据失败");
                }
            } else {
                resultAccnt.setDesc(PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULLS);//分账状态描述
                resultAccnt.setCode(PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULL);//分账状态
                resultAccnt.setStatus("2");
            }
            //插入在途1账户资金明细;更新在途1账户总额
            int flag2 = insertHisOnway(transcationNo, accnt, mchAccntOnway, mchNo, amount,date);
            if (flag2 < 0) {
                _log.info("插入在途1资金明细数据失败");
            }
            //6.此时分账成功，更新分账状态
            resultAccnt.setCode("0000");
            resultAccnt.setStatus("1");
            successCount++;
            resultAccnt.setAmountAfterEvent(afertAmt);//分账后账户余额 //
        }
    }

    private void updateHisProfileByTime(String mchNo, Date dates, Long amount,String mchAccntNo) {
        HisAccntProfile hisAccntProfile = new HisAccntProfile();
        hisAccntProfile.setEventTime(dates);
        hisAccntProfile.setEventAmt(amount);
        hisAccntProfile.setMchNo(mchNo);
        hisAccntProfileMapper.updateHisProfileByTime(hisAccntProfile);
    }

    /**
     * 补账后，更新漏账的数据后的历史明细的事件前，事件后金额
     * @param mchNo
     * @param dates
     */
    private void updateHisMchSubByTime(String mchNo, Date dates, Long amount,String mchAccntNo) {
        HisAccntMchSub hisAccntMchSub = new HisAccntMchSub();
        hisAccntMchSub.setEventTime(dates);
        hisAccntMchSub.setEventAmt(amount);
        hisAccntMchSub.setMchNo(mchNo);
        hisAccntMchSub.setMchAccntNo(mchAccntNo);
        hisAccntMchSubMapper.updateHisMchSubByTime(hisAccntMchSub);
    }


    /**
     * 判断订单号是否重复
     * param mchNo 商户号
     * param orderNo 订单号
     * param resultAccnt 返回分账实体
     * return
     */
    private boolean checkOrderNo(String mchNo, String orderNo, Accnt resultAccnt) {
        boolean flag = false;
        //子商户账户明细
        List<HisAccntMchSub> hisAccntMchSubList = baseService.selectHisAccntMchSub(mchNo, orderNo);
        //分润账户明细
        List<HisAccntProfile> hisAccntProfiles = baseService.selectHisAccntProfile(mchNo, orderNo);
        //待结算供应商账户明细
        List<HisAccntSupplierAssurance> hisAccntSupplierAssurances = baseService.selectHisAccntSupplierAss(mchNo, orderNo);
        if (ToolUtil.isNotEmpty(hisAccntMchSubList)) {
            resultAccnt.setDesc(PayConstant.RETURN_DEPOSIT_ORDER_NO_EXISTS);
            resultAccnt.setCode(PayConstant.RETURN_DEPOSIT_ORDER_NO_EXIST);
            resultAccnt.setStatus("2");
            resultAccnt.setAmountAfterEvent(hisAccntMchSubList.get(0).getAccntAmtAfter( ));//分账后账户余额 //
            flag = true;
        } else if (ToolUtil.isNotEmpty(hisAccntProfiles)) {
            resultAccnt.setDesc(PayConstant.RETURN_DEPOSIT_ORDER_NO_EXISTS);
            resultAccnt.setCode(PayConstant.RETURN_DEPOSIT_ORDER_NO_EXIST);
            resultAccnt.setStatus("2");
            resultAccnt.setAmountAfterEvent(hisAccntProfiles.get(0).getAccntAmtAfter( ));//分账后账户余额 //
            flag = true;
        } else if (ToolUtil.isNotEmpty(hisAccntSupplierAssurances)) {
            resultAccnt.setDesc(PayConstant.RETURN_DEPOSIT_ORDER_NO_EXISTS);
            resultAccnt.setCode(PayConstant.RETURN_DEPOSIT_ORDER_NO_EXIST);
            resultAccnt.setStatus("2");
            resultAccnt.setAmountAfterEvent(hisAccntSupplierAssurances.get(0).getAccntAmtAfter( ));//分账后账户余额 //
            flag = true;
        }
        return flag;
    }


    /**
     * 处理平台优惠逻辑
     *
     * @param accnt         请求分账实体
     * @param accntType     请求分账类型
     * @param amount        请求分账金额
     * @param mchNo         商户号
     * @param mchAccntNo    子账户号
     * @param transTime     交易时间
     * @param transcationNo 事务号
     * @param amt           事件发生前余额
     * @return
     */
    private Long promotion(Accnt accnt, String accntType, Long amount, String mchNo, String mchAccntNo, Date transTime, String transcationNo, Long amt,Date date) {
        //如果实际入账金额小于分账金额，且存在平台提供活动资金start 2018-11-5
        //如果有活动资金，且是子商户账户，例如分账金额90，活动资金是30，则更新账户金额为60，准备金往子账户转30，不记录还准备交易表
        //更改准备金账户余额
        MchAccnt prepayAccnt = new MchAccnt( );
        prepayAccnt.setAccntType(PayConstant.DEPOSIT_PREPAY);
        prepayAccnt.setMchNo(mchNo);
        prepayAccnt = baseService.baseSelectMchAccnt(prepayAccnt);
        Long prepayAmt = prepayAccnt.getRemainAmt( );
        updatePrepay(prepayAccnt, -accnt.getPromotionAmt( ));
        //更改子账户余额
        updateMchAccnt(mchNo, mchAccntNo, accnt.getPromotionAmt( ));
        //插入准备金账务明细
        insertHisPrepay(transTime, mchNo, accnt.getOrderNo( ), -accnt.getPromotionAmt( ), prepayAmt, accnt.getPromotionType( ));
        //插入子账户账务明细
        insertHisMchSub(transcationNo, accnt, mchNo, amt, accnt.getPromotionAmt( ), amt + accnt.getPromotionAmt(),date);
        //子账户余额已经变更
        amt = amt + accnt.getPromotionAmt( );
        //end 2018-11-5
        return amt;
    }

    /**
     * 校验参数有效性
     * param mchNo
     * param accnt
     * param resultAccnt
     * return
     */
    private boolean checkMustPramter(String mchNo, Accnt accnt, Accnt resultAccnt) {
        boolean flag = false;
        Map<String, String> checkParameterMap = checkMust(mchNo, accnt);
        if (!checkParameterMap.get("code").equals("0000")) {//参数校验失败
            resultAccnt.setDesc(checkParameterMap.get("desc"));
            resultAccnt.setCode(checkParameterMap.get("code"));
            resultAccnt.setStatus("2");
            resultAccnt.setAmountAfterEvent(0L);//分账后账户余额 //
            flag = true;
        }
        return flag;
    }

    private boolean checkMustPramterPay(String mchNo, Accnt accnt, Accnt resultAccnt) {
        boolean flag = false;
        Map<String, String> checkParameterMap = checkMustPay(mchNo, accnt);

        if (!checkParameterMap.get("code").equals("0000")) {//参数校验失败
            resultAccnt.setDesc(checkParameterMap.get("desc"));
//            resultAccnt.setCode(checkParameterMap.get("code"));
            resultAccnt.setStatus("2");
            resultAccnt.setAmountAfterEvent(0L);//分账后账户余额
            flag = true;
        }
        return flag;
    }

    private boolean checkMustPramterRefund(String mchNo, Accnt accnt, Accnt resultAccnt, String transNo) {
        boolean flag = false;
        Map<String, String> checkParameterMap = checkMustRefund(mchNo, accnt, transNo);

        if (!checkParameterMap.get("code").equals("0000")) {//参数校验失败
            resultAccnt.setDesc(checkParameterMap.get("desc"));
//            resultAccnt.setCode(checkParameterMap.get("code"));
            resultAccnt.setStatus("2");
            resultAccnt.setAmountAfterEvent(0L);//分账后账户余额
            flag = true;
        }
        return flag;
    }

    private boolean checkMustPramterOther(String mchNo, Accnt accnt, Accnt resultAccnt) {
        boolean flag = false;
        Map<String, String> checkParameterMap = checkMustOther(mchNo, accnt);

        if (!checkParameterMap.get("code").equals("0000")) {//参数校验失败
            resultAccnt.setDesc(checkParameterMap.get("desc"));
//            resultAccnt.setCode(checkParameterMap.get("code"));
            resultAccnt.setStatus("2");
            resultAccnt.setAmountAfterEvent(0L);//分账后账户余额
            flag = true;
        }
        return flag;
    }

    /**
     * 查询待结算供应商子账户号
     *
     * @param mchNo         商户号
     * @param outMchAccntNo 外部子账户号
     * @return
     */
    private String querySuplierMchNo(String mchNo, String outMchAccntNo) {
        MchAccnt accnt = new MchAccnt( );
        accnt.setMchNo(mchNo);
        accnt.setOutMchAccntNo(outMchAccntNo);
        accnt.setAccntType(PayConstant.DEPOSIT_SUPPLIER_ASSURANCE);
        List<MchAccnt> mchAccntList = mchAccntMapper.selectMchAccnt(accnt);
        if (ToolUtil.isNotEmpty(mchAccntList)) {
            return mchAccntList.get(0).getMchAccntNo( );
        }
        return null;
    }


    /**
     * 计算分账的手续费
     *
     * @param amount
     * @param accntList
     * @return
     */
    private int getTransFee(Long amount, List<Accnt> accntList) {
        //计算分账的手续费 start
        int amtcount = 0;
        String chargeRate = "";
        for (Accnt accnt : accntList) {
            if (ToolUtil.isNotEmpty(accnt.getChargeRate( )) && !"refund".equals(accnt.getDispatchEvent( ))) {//如果需要计算手续费
                //计算出分账的总额
                String dispatchType = accnt.getDispatchType( );
                amount = accnt.getAmount( );//单次请求分账金额
                if (dispatchType.equals("2")) {//1:正交易，2：反交易
                    amount = 0 - amount;
                }
                amtcount += amount;
                //计算出分账的手续费
            }
            chargeRate = accnt.getChargeRate( );
        }
        int transFee = 0;
        if (amount != 0) {
            transFee = new BigDecimal(amtcount).multiply(new BigDecimal(chargeRate)).setScale(3, java.math.BigDecimal.ROUND_HALF_UP).intValue( );
        }
        //计算分账的手续费 end
        return transFee;
    }

    /**
     * 计算分账手续费（商户支付记账接口、商户非支付退款类记账接口）
     * @param amount
     * @param accntList
     * @return
     */
    private int getTransFeeEvent(Long amount, String chargeRate, List<Accnt> accntList) {
        //计算分账的手续费 start
        int amtcount = 0;
        for (Accnt accnt : accntList) {
            if (ToolUtil.isNotEmpty(chargeRate) && !"refund".equals(accnt.getDispatchEvent())){ //如果需要计算手续费
                //计算出分账的总额
                String dispatchType = accnt.getDispatchType( );
                amount = accnt.getAmount( );//单次请求分账金额
                if (dispatchType.equals("2")) {//1:正交易，2：反交易
                    amount = 0 - amount;
                }
                amtcount += amount;
            }
        }
        int transFee = 0;
        if (amount != 0) {
            transFee = new BigDecimal(amtcount).multiply(new BigDecimal(chargeRate)).setScale(3, java.math.BigDecimal.ROUND_HALF_UP).intValue( );
        }
        //计算分账的手续费 end
        return transFee;
    }

    /**
     * 记录准备金历史交易明细
     * <p>
     * param mchNo           商户号
     * param orderNo         订单号
     * param eventAmt        事件金额
     * param beforePrepayAmt
     */
    private void insertHisPrepay(Date transTime, String mchNo, String orderNo, Long eventAmt, Long beforePrepayAmt, String event) {

        HisAccntPrepay hisAccntPrepay = new HisAccntPrepay( );
        hisAccntPrepay.setMchNo(mchNo);//商户号
        hisAccntPrepay.setOrderNo(orderNo);//订单号
        hisAccntPrepay.setTransactionNo("");//事务号
        hisAccntPrepay.setEvent(event);//
        hisAccntPrepay.setEventAmt(eventAmt);//事件金额(超出提现账户可用余额部分)
        hisAccntPrepay.setEventTime(transTime);
        hisAccntPrepay.setAccntAmtBefore(beforePrepayAmt);//事件发生前余额
        hisAccntPrepay.setAccntAmtAfter(beforePrepayAmt + hisAccntPrepay.getEventAmt( ));//事件发生后金额
        hisAccntPrepay.setCreateTime(new DateTime( ));
        baseService.insertHisPrepay(hisAccntPrepay);
    }

    private void updatePrepay(MchAccnt prepayAccnt, Long amt) {
        prepayAccnt.setRemainAmt(amt);
        prepayAccnt.setUpdateTime(new DateTime( ));
        baseService.updateMchAmtNoZero(prepayAccnt);
    }

    /**
     * 请求分账信息校验
     * <p>
     * param accnt
     * return
     */
    public Map<String, String> checkMust(String mchNo, Accnt accnt) {
        if (ToolUtil.isEmpty(accnt.getMchAccntNo( ))) {
            return createMap("账户号不能为空", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }
        if (ToolUtil.isEmpty(accnt.getAmount( )) || !ToolUtil.isNum(accnt.getAmount( ))) {
            return createMap("分账金额不合法", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }

        if (ToolUtil.isEmpty(accnt.getDispatchEvent( ))) {
            return createMap("分账事件不能为空", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }
        if (ToolUtil.isEmpty(accnt.getDispatchType( )) || (!accnt.getDispatchType( ).equals("1") && !"2".equals(accnt.getDispatchType( )))) {
            return createMap("分账类型不合法", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }
        if (ToolUtil.isEmpty(accnt.getOrderNo( ))) {
            return createMap("订单号不能为空", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }
        if (ToolUtil.isEmpty(accnt.getTransNo( ))) {
            return createMap("交易流水号不能为空", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }
        List<MchConfig> mchConfigList;//商户配置信息
        MchConfig mchConfig = new MchConfig();
        mchConfig.setMchNo(mchNo);
        mchConfig.setAccntType("0");
        //根据电商平台号，查询商户配置信息
        mchConfigList = iMchConfigService.listCongi(mchConfig);
        MchConfig config = mchConfigList.get(0);



        if (ToolUtil.isNotEmpty(accnt.getChargeRate( )) && (ToolUtil.isNum(accnt.getChargeRate( )) || Double.valueOf(accnt.getChargeRate( )) > 0.1)) {
            return createMap("手续费费率不合法", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }
        //子账户号必须存在
        MchAccnt mchAccnt = new MchAccnt( );
        mchAccnt.setMchAccntNo(accnt.getMchAccntNo( ));
        mchAccnt.setMchNo(mchNo);
        if (baseService.baseSelectMchAccnt(mchAccnt) == null) {
            return createMap(PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULLS, PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULL);
        }
        //如果版本号为1.0.2,则需要校验支付成功时间，退款交易流水号
        if(versionNo.equals(config.getVersionNo())){
            if (ToolUtil.isEmpty(accnt.getTransTime())) {
                    return createMap("支付成功时间不能为空", PayConstant.RETURN_DEPOSIT_MUST_NULL);
            }
            /*if (ToolUtil.isEmpty(accnt.getTransChannel())) {
                return createMap("支付所属通道", PayConstant.RETURN_DEPOSIT_MUST_NULL);
            }*/
            //如果分账类型是退款，则退款交易流水号不可为空
            if (PayConstant.DEPOSIT_EVENT_REFUND.equals(accnt.getDispatchEvent())) {
                if (ToolUtil.isEmpty(accnt.getRefundTransNo())) {
                    return createMap("退款交易流水号不可为空", PayConstant.RETURN_DEPOSIT_MUST_NULL);
                }
                //如果分账类型是退款，则退款交易流水号对应的支付交易流水号必须存在
                if(ToolUtil.isEmpty(baseService.selectHisAccntMchSubByTransNo(mchNo,accnt.getTransNo()))){
                    return createMap(PayConstant.RETURN_DEPOSIT_DISPATCH_REFERRORS, PayConstant.RETURN_DEPOSIT_DISPATCH_REFERROR);
                }
            }
        }





        return createMap("", "0000");
    }

    /**
     * 商户支付记账参数校验
     * <p>
     * param accnt
     * return
     */
    public Map<String, String> checkMustPay(String mchNo, Accnt accnt) {
        if (ToolUtil.isEmpty(accnt.getMchAccntNo( ))) {
            return createMap("账户号不能为空", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }

        if (ToolUtil.isEmpty(accnt.getAmount( )) || !ToolUtil.isNum(accnt.getAmount( ))) {
            return createMap("分账金额不合法", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }

        if (ToolUtil.isEmpty(accnt.getDispatchEvent( ))) {
            return createMap("分账事件不能为空", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }

        if (ToolUtil.isEmpty(accnt.getDispatchType( )) || (!accnt.getDispatchType( ).equals("1") && !"2".equals(accnt.getDispatchType( )))) {
            return createMap("分账类型不合法", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }

        if (ToolUtil.isEmpty(accnt.getOrderNo( ))) {
            return createMap("订单号不能为空", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }

        //子账户号必须存在
        MchAccnt mchAccnt = new MchAccnt( );
        mchAccnt.setMchAccntNo(accnt.getMchAccntNo( ));
        mchAccnt.setMchNo(mchNo);
        if (baseService.baseSelectMchAccnt(mchAccnt) == null) {
            return createMap(PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULLS, PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULL);
        }

        return createMap("", "0000");
    }

    /**
     * 商户退款记账参数校验
     * <p>
     * param accnt
     * return
     */
    public Map<String, String> checkMustRefund(String mchNo, Accnt accnt, String transNo) {
        if (ToolUtil.isEmpty(accnt.getMchAccntNo( ))) {
            return createMap("账户号不能为空", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }

        if (ToolUtil.isEmpty(accnt.getAmount( )) || !ToolUtil.isNum(accnt.getAmount( ))) {
            return createMap("分账金额不合法", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }

        if (ToolUtil.isEmpty(accnt.getDispatchEvent( ))) {
            return createMap("分账事件不能为空", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }

        if (ToolUtil.isEmpty(accnt.getDispatchType( )) || (!accnt.getDispatchType( ).equals("1") && !"2".equals(accnt.getDispatchType( )))) {
            return createMap("分账类型不合法", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }

        if (ToolUtil.isEmpty(accnt.getOrderNo( ))) {
            return createMap("订单号不能为空", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }

        //子账户号必须存在
        MchAccnt mchAccnt = new MchAccnt( );
        mchAccnt.setMchAccntNo(accnt.getMchAccntNo( ));
        mchAccnt.setMchNo(mchNo);
        if (baseService.baseSelectMchAccnt(mchAccnt) == null) {
            return createMap(PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULLS, PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULL);
        }

        //分账类型是退款，则退款交易流水号不可为空
        if (PayConstant.DEPOSIT_EVENT_REFUND.equals(accnt.getDispatchEvent())) {
            //分账类型是退款，则退款交易流水号对应的支付交易流水号必须存在
            if(ToolUtil.isEmpty(baseService.selectHisAccntMchSubByTransNo(mchNo, transNo))){
                return createMap("退款对应的交易不存在，请查证！", PayConstant.RETURN_DEPOSIT_MUST_NULL);
            }
        }

        return createMap("", "0000");
    }

    /**
     * 商户非支付退款类记账参数校验
     * <p>
     * param accnt
     * return
     */
    public Map<String, String> checkMustOther(String mchNo, Accnt accnt) {
        if (ToolUtil.isEmpty(accnt.getMchAccntNo( ))) {
            return createMap("账户号不能为空", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }

        if (ToolUtil.isEmpty(accnt.getAmount( )) || !ToolUtil.isNum(accnt.getAmount( ))) {
            return createMap("分账金额不合法", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }

        if (ToolUtil.isEmpty(accnt.getDispatchEvent( ))) {
            return createMap("分账事件不能为空", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }

        if (ToolUtil.isEmpty(accnt.getDispatchType( )) || (!accnt.getDispatchType( ).equals("1") && !"2".equals(accnt.getDispatchType( )))) {
            return createMap("分账类型不合法", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }

        if (ToolUtil.isEmpty(accnt.getOrderNo( ))) {
            return createMap("订单号不能为空", PayConstant.RETURN_DEPOSIT_MUST_NULL);
        }

        //子账户号必须存在
        MchAccnt mchAccnt = new MchAccnt( );
        mchAccnt.setMchAccntNo(accnt.getMchAccntNo( ));
        mchAccnt.setMchNo(mchNo);
        if (baseService.baseSelectMchAccnt(mchAccnt) == null) {
            return createMap(PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULLS, PayConstant.RETURN_DEPOSIT_MCHSUBNO_NULL);
        }

        return createMap("", "0000");
    }

    /**
     * 根据电商平台号，账户号查询子商户账户信息
     * <p>
     * param mchNo
     * param mchAccntNo
     * return
     */
    private MchAccnt queryMchAccntByMchNo(String mchNo, String mchAccntNo) {
        MchAccnt mchAccnt = new MchAccnt( );
        MchAccnt mchAccntBefore = null;
        mchAccnt.setMchAccntNo(mchAccntNo);//账户号
        mchAccnt.setMchNo(mchNo);
        List<MchAccnt> mchAccntList = mchAccntMapper.selectMchAccnt(mchAccnt);//根据账户号商户号，查询账户信息
        if (ToolUtil.isNotEmpty(mchAccntList)) {
            mchAccntBefore = mchAccntList.get(0);
        }
        return mchAccntBefore;
    }

    /**
     * 查询在途账户信息
     * <p>
     * param mchNo
     * return
     */
    private MchAccnt queryMchOnway(String mchNo) {
        MchAccnt mchresultAccnt = new MchAccnt( );
        mchresultAccnt.setAccntType("onway");
        mchresultAccnt.setMchNo(mchNo);
        return baseService.baseSelectMchAccnt(mchresultAccnt);
    }

    /**
     * 更新分账账户信息
     * <p>
     * param
     * param
     * return
     */
    private int updateMchAccnt(String mchNo, String mchAccntNo, Long amount) {
        MchAccnt mchAccntBefore = new MchAccnt( );
        mchAccntBefore.setMchNo(mchNo);
        mchAccntBefore.setMchAccntNo(mchAccntNo);
        mchAccntBefore.setRemainAmt(amount);
        mchAccntBefore.setUpdateTime(new DateTime( ));
        return baseService.updateMchAmtNoZero(mchAccntBefore);
    }

    /**
     * 更新分润账户余额
     * <p>
     * param
     * param amount
     * return
     */
    private int updateMchProfit(Long transFeeGap, String mchNo) {
        MchAccnt mchAccntProfit = new MchAccnt();
        mchAccntProfit.setAccntType("profit");
        mchAccntProfit.setMchNo(mchNo);
        mchAccntProfit.setUpdateTime(new DateTime());
        mchAccntProfit.setRemainAmt(transFeeGap);
        return baseService.updateMchAmtNoZero(mchAccntProfit);
    }

    /**
     * 更新在途账户信息
     * <p>
     * param
     * param amount
     * return
     */
    private int updateMchOnway(Long amount, String mchNo) {
        MchAccnt mchAccntOnway = new MchAccnt( );
        mchAccntOnway.setAccntType("onway");
        mchAccntOnway.setMchNo(mchNo);
        mchAccntOnway.setUpdateTime(new DateTime( ));
        mchAccntOnway.setRemainAmt(-amount);
        return baseService.updateMchAmtNoZero(mchAccntOnway);
    }

    /**
     * 插入事务表
     * <p>
     * param req
     * return
     */
    private int insertTranction(String transcationNo, DispatchInfo req) {
        DepositTransaction des = new DepositTransaction( );
        //插入事务
        des.setTransactionNo(transcationNo);//事务号
        des.setOutTransNo(req.getOutTransNo( ));//外部追踪号
        des.setIdMchAccntChargeUp(0);
        des.setCreateTime(new DateTime( ));//创建时间
        des.setTransactionType("dispatch");//事务类型
        des.setUpdateTime(new DateTime( ));//更新时间
        des.setMchNo(req.getMchNo( ));//商户号
        //更新事务表
        return depositTransactionMapper.insert(des);
    }

    /**
     * 插入事务表
     * <p>
     * param req
     * return
     */
    private int insertTranction(String transcationNo, DispatchPayInfo req) {
        DepositTransaction des = new DepositTransaction( );
        //插入事务
        des.setTransactionNo(transcationNo);//事务号
        des.setOutTransNo(req.getOutTransNo( ));//外部追踪号
        des.setIdMchAccntChargeUp(0);
        des.setCreateTime(new DateTime( ));//创建时间
        des.setTransactionType("dispatch");//事务类型
        des.setUpdateTime(new DateTime( ));//更新时间
        des.setMchNo(req.getMchNo( ));//商户号
        //更新事务表
        return depositTransactionMapper.insert(des);
    }

    /**
     * 插入子商户账户资金明细数据
     *
     * @param transcationNo
     * @param accnt
     * @param mchNo
     * @param amt           事件发生前金额
     * @param amount        事件金额
     * @param afertAmt      事件发生后金额
     * @return
     */
    private int insertHisMchSub(String transcationNo, Accnt accnt, String mchNo, Long amt, Long amount, Long afertAmt,Date date) {
        //插入子商户账户资金明细表
        HisAccntMchSub hisAccntMchSub = new HisAccntMchSub( );
        hisAccntMchSub.setMchNo(mchNo);//商户号
        hisAccntMchSub.setMchAccntNo(accnt.getMchAccntNo( ));//子商户账户号
        hisAccntMchSub.setOrderNo(accnt.getOrderNo( ));//订单号
        hisAccntMchSub.setTransactionNo(transcationNo);//事务号
        hisAccntMchSub.setEvent(accnt.getDispatchEvent( ));//事件名称
        hisAccntMchSub.setEventAmt(amount);//事件金额
        hisAccntMchSub.setEventTime(date);
        hisAccntMchSub.setAccntAmtBefore(amt);//事件发生前余额(高并发情况下，如何保证数据准确？)
        hisAccntMchSub.setAccntAmtAfter(afertAmt);//事件发生后金额
        hisAccntMchSub.setCreateTime(date);
        hisAccntMchSub.setTransNo(accnt.getTransNo( ));//交易流水号
        hisAccntMchSub.setRefundTransNo(accnt.getRefundTransNo());//退款交易流水号
        hisAccntMchSub.setSettleDuration(accnt.getSettleDuration( ));//结算周期
        hisAccntMchSub.setBusinessType(accnt.getBusinessType( ));//业务类型
        hisAccntMchSub.setTransTime(accnt.getTransTime());//支付成功时间
        hisAccntMchSub.setTransChannel(accnt.getTransChannel());//支付所属通道
        return baseService.insertHisMchASub(hisAccntMchSub);
    }

    /**
     * 插入分润账户资金明细数据
     * <p>
     * param accnt
     * param mchNo
     * param amt
     * param afertAmt
     * return
     */
    public int insertHisMchProfit(String transcationNo, Accnt accnt, String mchNo, Long amt, Long amount, Long afertAmt,Date date) {
        //插入分润商户账户资金明细表
        HisAccntProfile hisAccntProfile = new HisAccntProfile( );
        hisAccntProfile.setMchNo(mchNo);
        hisAccntProfile.setOrderNo(accnt.getOrderNo( ));//订单号
        hisAccntProfile.setTransactionNo(transcationNo);//事务号
        hisAccntProfile.setEvent(accnt.getDispatchEvent( ));//事件名称
        hisAccntProfile.setEventAmt(amount);//事件金额
        hisAccntProfile.setEventTime(date);//事件时间
        hisAccntProfile.setAccntAmtBefore(amt);//事件发生前余额
        hisAccntProfile.setAccntAmtAfter(afertAmt);//事件发生后金额
        hisAccntProfile.setCreateTime(date);//创建时间
        hisAccntProfile.setTransNo(accnt.getTransNo( ));//交易流水号
        hisAccntProfile.setRefundTransNo(accnt.getRefundTransNo());//退款交易流水号
        hisAccntProfile.setSettleDuration(accnt.getSettleDuration( ));//结算周期
        hisAccntProfile.setBusinessType(accnt.getBusinessType( ));//业务类型
        hisAccntProfile.setTransTime(accnt.getTransTime());
        hisAccntProfile.setTransChannel(accnt.getTransChannel());
        return baseService.insertHisProfile(hisAccntProfile);
    }

    /**
     * 插入供应商待结算账户明细数据
     * <p>
     * param accnt
     * param mchNo
     * param amt
     * param afertAmt
     * return
     */
    public int insertHisSupplierAss(String transcationNo, Accnt accnt, String mchNo, Long amt, Long amount, Long afertAmt,Date date) {
        //插入供应商待结算商户账户资金明细表
        HisAccntSupplierAssurance hisAccntSupplierAss = new HisAccntSupplierAssurance( );
        hisAccntSupplierAss.setMchNo(mchNo);
        hisAccntSupplierAss.setMchAccntNo(accnt.getMchAccntNo( ));//子商户账户号
        hisAccntSupplierAss.setOrderNo(accnt.getOrderNo( ));//订单号
        hisAccntSupplierAss.setTransactionNo(transcationNo);//事务号
        hisAccntSupplierAss.setEvent(accnt.getDispatchEvent( ));//事件名称
        hisAccntSupplierAss.setEventAmt(amount);//事件金额
        hisAccntSupplierAss.setEventTime(date);//事件时间
        hisAccntSupplierAss.setAccntAmtBefore(amt);//事件发生前余额
        hisAccntSupplierAss.setAccntAmtAfter(afertAmt);//事件发生后金额
        hisAccntSupplierAss.setCreateTime(date);//创建时间
        hisAccntSupplierAss.setTransNo(accnt.getTransNo( ));//交易流水号
        hisAccntSupplierAss.setRefundTransNo(accnt.getRefundTransNo());//退款交易流水号
        hisAccntSupplierAss.setSettleDuration(accnt.getSettleDuration( ));//结算周期
        hisAccntSupplierAss.setBusinessType(accnt.getBusinessType( ));//业务类型
        hisAccntSupplierAss.setTransTime(accnt.getTransTime());
        hisAccntSupplierAss.setTransChannel(accnt.getTransChannel());
        return baseService.insertHisSupplierAss(hisAccntSupplierAss);
    }

    /**
     * 插入在途1资金明细数据
     * <p>
     * param accnt
     * param mchAccntOnway
     * param mchNo
     * param amount
     * return
     */
    private int insertHisOnway(String transcationNo, Accnt accnt, MchAccnt mchAccntOnway, String mchNo, Long amount,Date date) {
        //插入在途资金明细表----------
        HisAccntOnway hisAccntOnway = new HisAccntOnway( );
        hisAccntOnway.setMchNo(mchNo);//商户号
        hisAccntOnway.setOrderNo(accnt.getOrderNo( ));//订单号
        hisAccntOnway.setTransactionNo(transcationNo);//事务号
        hisAccntOnway.setEvent(accnt.getDispatchEvent( ));//
        hisAccntOnway.setEventAmt(-amount);//事件金额
        hisAccntOnway.setEventTime(date);//事件发生时间
        hisAccntOnway.setType(accnt.getTransNo( ));
        hisAccntOnway.setAccntAmtBefore(mchAccntOnway.getRemainAmt( ));//事件发生前余额
        hisAccntOnway.setAccntAmtAfter(mchAccntOnway.getRemainAmt( ) - amount);//事件发生后金额
        hisAccntOnway.setCreateTime(date);
        if("supplement".equals(accnt.getDispatchEvent())){
            hisAccntOnway.setCreateTime(accnt.getReconTime());
        }
        hisAccntOnway.setType("detailed");//历史数据类型
        hisAccntOnway.setTransNo(accnt.getTransNo( ));//交易流水号
        hisAccntOnway.setTransTime(accnt.getTransTime());//交易完成时间
        hisAccntOnway.setTransChannel(accnt.getTransChannel());//所属支付通道
        hisAccntOnway.setRefundTransNo(accnt.getRefundTransNo());//退款交易流水号
        return baseService.insertHisOnway(hisAccntOnway);
    }

    /**
     * 更新在途1总额
     * <p>
     * param mchNo
     * param amount
     * return
     */
    private int updateHisOnway(String mchNo, Long amount) {
        HisAccntOnway hisAccntOnwayInfo = new HisAccntOnway( );
        hisAccntOnwayInfo.setMchNo(mchNo);//电商平台号
        hisAccntOnwayInfo.setType("count");//记账类型
        hisAccntOnwayInfo.setBalance(-amount);
        hisAccntOnwayInfo.setUpdateTime(new DateTime( ));
        return baseService.updateHisAccntOnway(hisAccntOnwayInfo);
    }


    /**
     * 组装参数校验map
     * <p>
     * param desc
     * param code
     * return
     */
    private Map<String, String> createMap(String desc, String code) {
        Map<String, String> resultMap = new ConcurrentHashMap<>( );
        resultMap.put("desc", desc);
        resultMap.put("code", code);
        return resultMap;
    }



}
